package znet

import (
	"fmt"
	"gitee.com/jiangjiali/z-tcp/helper/snowflake"
	"gitee.com/jiangjiali/z-tcp/utils"
	"gitee.com/jiangjiali/z-tcp/ziface"
	"net"
)

var logo = `
  ___ ___  ___ ___ 
 / __/ _ \| _ \ __|
| (_| (_) |   / _| 
 \___\___/|_|_\___|`

// Server 接口实现，定义一个Server服务类
type Server struct {
	//服务器的名称
	Name string
	//tcp4 or other
	IPVersion string
	//服务绑定的IP地址
	IP string
	//服务绑定的端口
	Port int
	//当前Server的消息管理模块，用来绑定MsgId和对应的处理方法
	msgHandler ziface.IMsgHandle
	//当前Server的链接管理器
	ConnMgr ziface.IConnManager
	//该Server的连接创建时Hook函数
	OnConnStart func(conn ziface.IConnection)
	//该Server的连接断开时的Hook函数
	OnConnStop func(conn ziface.IConnection)

	packet ziface.Packet
}

// NewServer 创建一个服务器句柄
func NewServer(opts ...Option) ziface.IServer {
	printLogo() //打印LOGO
	s := &Server{
		Name:       utils.GlobalObject.Name,
		IPVersion:  "tcp4",
		IP:         utils.GlobalObject.Host,
		Port:       utils.GlobalObject.Port,
		msgHandler: NewMsgHandle(),
		ConnMgr:    NewConnManager(),
		packet:     NewDataPack(),
	}

	for _, opt := range opts {
		opt(s)
	}
	return s
}

//============== 实现 ziface.IServer 里的全部接口方法 ========

// Start 开启网络服务
func (s *Server) Start() {
	// 开启一个go去做服务端监听业务
	go func() {
		//0 启动worker工作池机制
		s.msgHandler.StartWorkerPool()

		//1 获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("解析TCP地址 错误:", err)
			return
		}

		//2 监听服务器地址
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			panic(err)
		}

		// 初始化限制器
		l := NewLimiter()

		//已经监听成功
		fmt.Printf("服务端: %s, %s:%d 正在监听...\n", s.Name, s.IP, s.Port)

		//3 启动server网络连接业务
		for {
			//3.1 阻塞等待客户端建立连接请求
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Println("TCP认证错误:", err)
				continue
			}
			fmt.Println("获取连接远程地址:", conn.RemoteAddr().String())

			// 3.2 服务器 在时间内限流
			if l.IsAvailable() {
				// 连接数限制
				if s.ConnMgr.Len() >= utils.GlobalObject.MaxConn {
					err := conn.Close()
					if err == nil {
						continue
					}
				} else {
					l.Increase()
				}
			} else {
				err := conn.Close()
				if err == nil {
					continue
				}
			}

			//3.3 处理该新连接请求的 业务 方法， 此时应该有 handler 和 conn是绑定的
			connId := snowflake.ID()
			dealConn := NewConntion(s, conn, int64(connId), s.msgHandler)

			//3.4 启动当前链接的处理业务
			go dealConn.Start()
		}
	}()
}

// Stop 停止服务
func (s *Server) Stop() {
	fmt.Printf("[停止] 服务端:%s", s.Name)

	//将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
	s.ConnMgr.ClearConn()
}

// Serve 运行服务
func (s *Server) Serve() {
	//开启网络服务
	s.Start()

	//TODO Server.Serve() 是否在启动服务的时候 还要处理其他的事情呢 可以在这里添加

	//阻塞,否则主Go退出， listenner的go将会退出
	select {}
}

// AddRouter 路由功能：给当前服务注册一个路由业务方法，供客户端链接处理使用
func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
	s.msgHandler.AddRouter(msgId, router)
}

// GetConnMgr 得到链接管理
func (s *Server) GetConnMgr() ziface.IConnManager {
	return s.ConnMgr
}

// SetOnConnStart 设置该Server的连接创建时Hook函数
func (s *Server) SetOnConnStart(hookFunc func(ziface.IConnection)) {
	s.OnConnStart = hookFunc
}

// SetOnConnStop 设置该Server的连接断开时的Hook函数
func (s *Server) SetOnConnStop(hookFunc func(ziface.IConnection)) {
	s.OnConnStop = hookFunc
}

// CallOnConnStart 调用连接OnConnStart Hook函数
func (s *Server) CallOnConnStart(conn ziface.IConnection) {
	if s.OnConnStart != nil {
		fmt.Println("---> Call 连接开始....")
		s.OnConnStart(conn)
	}
}

// CallOnConnStop 调用连接OnConnStop Hook函数
func (s *Server) CallOnConnStop(conn ziface.IConnection) {
	if s.OnConnStop != nil {
		fmt.Println("---> Call 连接停止....")
		s.OnConnStop(conn)
	}
}

func (s *Server) Packet() ziface.Packet {
	return s.packet
}

func printLogo() {
	fmt.Println(logo)
	fmt.Println(utils.NChars([]byte("-"),30))
	fmt.Printf("版本: %s, 最大连接数: %d, 最大包体容量: %d\n",
		utils.GlobalObject.Version,
		utils.GlobalObject.MaxConn,
		utils.GlobalObject.MaxPacketSize)
}
